
package com.hlkj.pay.app.merchant.ext.impl.gtzfpay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.date.DatePattern;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.GtzfScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.constant.GtzfPayConstant;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.constant.GtzfPayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.GtzfPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.GtzfpayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.dto.req.GtzfPayOrderRequest;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.utils.GtzfPayRsaUtil;
import com.hlkj.pay.app.merchant.ext.impl.gtzfpay.utils.HttpUtils;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.common.CommonAppDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.common.ICommonAppConfigService;
import com.hlkj.pay.util.AlipayOAuthUtils;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.util.WeChatOAuthUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.Objects;

/**
 * 主扫统一下单 用户扫支付码
 *
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = GtzfPayExtConstant.JSAPI_PAY)
public class GtzfPayJSAPIOrderExtPt extends GtzfPaySceneCommonPayOrder implements GtzfScenePayOrderExtPt {

    @Value("${hlkj.wxJsApi}")
    private String wxJsApi;

    @Value("${hlkj.aliJsApi}")
    private String aliJsApi;

    @Value("${hlkj.domain}")
    private String domain;

    private final ICommonAppConfigService commonAppConfigService;

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        // 配置转换
        GtzfPayConfig config = JsonUtils.parseObject(channelConfig, GtzfPayConfig.class);
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();

        try {
            //国通需回调地址要替换成映射地址
            channelPayOrderContext.setNotifyUrl(channelPayOrderContext.getNotifyUrl().replace(domain, config.getCallbackDomain()));
            GtzfpayAppChannelParams appChannelParams = easyPayAppChannelParams(merchantAppChannelDO, config);

            PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
            //易生 支付宝微信无小程序页面
            //初始化时返回支付路径
            if (!StringUtils.hasText(payOrderDO.getAuthCode()) && payWayDO.getType() == 1) {
                String payUrl = wxJsApi + "?payOrderNo=" + payOrderDO.getPayOrderNo();
                channelPayOrderContext.setPayInfo(payUrl);
                channelPayOrderContext.setPayDataType("pay_url");
                channelPayOrderContext.setRequestThird(false);
                return;
            }

            if (!StringUtils.hasText(payOrderDO.getAuthCode()) && payWayDO.getType() == 2) {
                String payUrl = aliJsApi + "?payOrderNo=" + payOrderDO.getPayOrderNo();
                channelPayOrderContext.setPayInfo(payUrl);
                channelPayOrderContext.setPayDataType("pay_url");
                channelPayOrderContext.setRequestThird(false);
                return;
            }

            CommonAppDO commonAppDO = null;
            String userId = "";
            if (payWayDO.getType() == 1) {
                commonAppDO = commonAppConfigService.detail(providerChannelConfigDO.getWechatDefaultPubId());
                if (commonAppDO == null) {
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    channelPayOrderContext.setRemark("国通统一下单失败，未配置微信appid");
                    return;
                }
                CommonResult<String> auth = WeChatOAuthUtils.getOpenId(commonAppDO.getAppId(), commonAppDO.getAppSecret(), payOrderDO.getAuthCode());
                if (!auth.isSuccess()) {
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    channelPayOrderContext.setRemark("国通获微信取授权信息失败，" + auth.getMsg());
                    return;
                }
                userId = auth.getData();
            } else if (payWayDO.getType() == 2) {
                commonAppDO = commonAppConfigService.detail(providerChannelConfigDO.getAlipayPubId());
                if (commonAppDO == null) {
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    channelPayOrderContext.setRemark("国通统一下单失败，未配置支付宝appid");
                    return;
                }
               CommonResult<String> auth = AlipayOAuthUtils.getToken(commonAppDO.getAppId(), commonAppDO.getAppSecret(), payOrderDO.getAuthCode());
                if (!auth.isSuccess()) {
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    channelPayOrderContext.setRemark("国通获取支付宝授权信息失败，" + auth.getMsg());
                    return;
                }
                userId = auth.getData();
            }
            String payType = getPayType(payWayDO);
            GtzfPayOrderRequest request = new GtzfPayOrderRequest();
            request.setAgetId(config.getAgetId());
            request.setCustId(appChannelParams.getCustId());
            request.setOrderNo(payOrderDO.getPayOrderNo());
            request.setTxamt(MerchantUtils.YuanToFen(payOrderDO.getAmount()));
            request.setOpenid(userId);

            if ("ALIPAY".equals(payOrderDO.getPayType())) {
                request.setPayWay("2");
                request.setZfbappid(commonAppDO.getAppId());
            } else if ("WECHAT".equals(payOrderDO.getPayType())) {
                request.setWxAppid(commonAppDO.getAppId());
                request.setPayWay("1");
                request.setTraType(payType);
            } else if ("UNION_APY".equals(payOrderDO.getPayType())) {
                request.setPayWay("3");
            }
            if (StringUtils.hasText(appChannelParams.getPayIp())) {
                request.setIp(appChannelParams.getPayIp());
            } else
                request.setIp(payOrderDO.getClientIp());
            request.setRemark(payOrderDO.getSubject());
            request.setTimeStamp(DateUtils.getDateString(DatePattern.PURE_DATETIME_PATTERN));
            request.setVersion("1.0.0");
            request.setAsyncNotify(channelPayOrderContext.getNotifyUrl());
            request.setSign(GtzfPayRsaUtil.encrypt(JSONUtil.parseObj(request), config.getMchPublicKey()));

            String url = domain(channelPayOrderContext.isTest()) + GtzfPayConstant.TRADE_JSAPI;
            log.info("国通JSAPI统一下单req参数:{}", JsonUtils.toJsonString(request));
            String response = HttpUtils.post(url, JsonUtils.toJsonString(request));
            log.info("国通JSAPI统一下单返回参数:{}", response);

            JSONObject rspBody = JsonUtils.parseObj(response);
            if ("000000".equals(rspBody.getStr("code"))) {
                JSONObject respStateInfo = rspBody.getJSONObject("data");
                channelPayOrderContext.setInsOrderNo(respStateInfo.getStr("orderNo"));

                channelPayOrderContext.setPayDataType("data");
                if ("ALIPAY".equals(payOrderDO.getPayType())) {
                    channelPayOrderContext.setPayInfo(respStateInfo.getStr("prepayid"));
                } else if ("WECHAT".equals(payOrderDO.getPayType())) {
                    JSONObject obj = new JSONObject();
                    obj.set("appId", respStateInfo.getStr("jsapiAppid"));
                    obj.set("timeStamp", respStateInfo.getStr("jsapiTimestamp"));
                    obj.set("nonceStr", respStateInfo.getStr("jsapiNoncestr"));
                    obj.set("package", respStateInfo.getStr("jsapiPackage"));
                    obj.set("signType", respStateInfo.getStr("jsapiSignType"));
                    obj.set("paySign", respStateInfo.getStr("jsapiPaySign"));
                    channelPayOrderContext.setPayInfo(obj.toString());
                } else if ("UNION_APY".equals(payOrderDO.getPayType())) {
                    channelPayOrderContext.setPayDataType("url");
                    channelPayOrderContext.setPayInfo(respStateInfo.getStr("redirecturl"));
                }
            } else {
                String respDesc = rspBody.getStr("msg");
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderContext.setRemark(respDesc);
                } else {
                    channelPayOrderContext.setRemark("国通提交JSAPI统一下单查询返回错误信息为空,错误码为:" + rspBody.getStr("code"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("国通提交JSAPI统一下单请求失败 message:{}", e.getMessage(), e);
            channelPayOrderContext.setRemark("国通提交JSAPI统一下单请求失败,失败信息" + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    private String getPayType(PayWayDO payWayDO) {
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType());
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(scenePayType) || Objects.isNull(payType)) return "";
        switch (payType) {
            case WECHAT:
                switch (scenePayType) {
                    case JSAPI:
                    case QR:
                    case APP:
                        return "5";
                    case MINI_APP:
                        return "8";
                }
        }
        return "";
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonCloseChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelClosePayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }
}
